﻿using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace WeixinPayResdk.Helper
{
    /// <summary>
    /// 解密微信通知结果帮助类
    /// 参考资料：https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_2.shtml
    /// .NET5环境使用该代码，需要安装Portable.BouncyCastle组件
    /// </summary>
    public abstract class AesGcmHelper
    {
        /// <summary>
        /// 解密回调数据 body主体数据
        /// </summary>
        /// <param name="associated_data">body数据</param>
        /// <param name="nonce">body数据</param>
        /// <param name="ciphertext">body数据</param>
        /// <param name="aesKey">32位的 商户平台 设置的密码</param>
        /// <returns></returns>
        public static string AesGcmDecrypt(string associated_data, string nonce, string ciphertext, string aesKey)
        {
            GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
            AeadParameters aeadParameters = new AeadParameters(
                new KeyParameter(Encoding.UTF8.GetBytes(aesKey)),
                128,
                Encoding.UTF8.GetBytes(nonce),
                Encoding.UTF8.GetBytes(associated_data));
            gcmBlockCipher.Init(false, aeadParameters);

            byte[] data = Convert.FromBase64String(ciphertext);
            byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
            int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
            gcmBlockCipher.DoFinal(plaintext, length);
            return Encoding.UTF8.GetString(plaintext);
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="Signature">私钥加密串-Wechatpay-Signature</param>
        /// <param name="signSourceString">验签名串-应答时间戳\n应答随机串\n应答报文主体\n</param>
        /// <param name="publickey">公钥</param>
        /// <returns></returns>
        public static bool VerifySign(string Signature, string signSourceString, string publickey)
        {
            byte[] pkey = Encoding.UTF8.GetBytes(publickey);
            var x509 = new X509Certificate2(pkey);

            var rsaParam = x509.GetRSAPublicKey().ExportParameters(false);
            var rsa = new RSACryptoServiceProvider();
            rsa.ImportParameters(rsaParam);

            var sha256 = new SHA256CryptoServiceProvider();
            var b = rsa.VerifyData(Encoding.UTF8.GetBytes(signSourceString), sha256, Convert.FromBase64String(Signature));
            return b;
        }
    }
}
